<template>
  <div id="player">
    <el-dialog
      :visible.sync="openDialog"
      @close="close"
      title="监控画面"
      center
      width="46%"
      top="50px"
      draggable="true"
      append-to-bodys
    >
      <!-- <el-tabs v-model="activeName" type="card" @tab-click="handleClick">
        <el-tab-pane label="监控" name="监控"></el-tab-pane>
        <el-tab-pane label="回放" name="回放"></el-tab-pane>
      </el-tabs> -->
      <div
        style="
          width: 100%;
          height: 100%;
          display: flex;
          justify-content: center;
        "
      >
        <div ref="videoContainer" v-if="openDialog">
          <!-- Video element will be injected here -->
        </div>
      </div>

      <!-- <test v-if="activeName === '监控'"></test> -->

      <div
        v-if="activeName === '回放' && false"
        style="
          display: flex;
          flex-direction: row;
          align-items: center;
          justify-content: space-between;
        "
      >
        <div>
          <span>时间: </span>
          <!-- <el-date-picker
            v-model="value1"
            type="datetime"
            @change="chooseTime"
            placeholder="选择日期时间"
          >
          </el-date-picker> -->
          <el-date-picker
            v-model="timeVal"
            type="datetimerange"
            range-separator="至"
            @change="chooseTime"
            start-placeholder="开始日期"
            end-placeholder="结束日期"
          >
          </el-date-picker>
        </div>
        <div>
          <span>倍速: </span>
          <el-select
            v-model="playbackSpeed"
            @change="selectChange"
            placeholder="选择倍速"
          >
            <el-option
              v-for="item in optionsPlaybackSpeed"
              :key="item.value"
              :label="item.label"
              :value="item.value"
            >
            </el-option>
          </el-select>
        </div>
      </div>
      <el-button
        type="primary"
        @click="handleCapture()"
        style="margin-top: 15px"
        >截图</el-button
      >

      <!-- <div class="progress-bar">
        进度条：拖动时定位到指定时间
        <input
          type="range"
          class="progress-slider"
          :min="0"
          :max="duration"
          :value="currentTime"
          @input="handleProgressDrag"
          @change="handleProgressChange"
          :disabled="!duration"
        />
        时间显示：当前时间 / 总时长
        <div class="time-display">
          {{ formatTime(currentTime) }} / {{ formatTime(duration) }}
        </div>
      </div> -->

      <!-- <el-image
        v-if="dataURLImage"
        style="width: 100px; height: 100px"
        :src="dataURLImage"
      ></el-image> -->
      <!-- <canvas id="canvas" width="640" height="360"></canvas> -->
    </el-dialog>

    <el-dialog
      :visible.sync="xiaFaDialog"
      @close="cloneTab"
      title="运营监控下发"
      center
      top="0"
      draggable="true"
      append-to-bodys
    >
      <el-form
        :rules="rules"
        :model="qusetionInfo"
        ref="supplierForm"
        label-width="0"
      >
        <div class="row-tow">
          <el-form-item prop="spec">
            <div style="display: flex">
              <p style="width: 60px; text-align: right; font-weight: bold">
                门店：
              </p>
              <div>{{ orderInfo.storeName || '' }}</div>
            </div>
          </el-form-item>
          <el-form-item prop="question">
            <div
              style="
                display: flex;
                justify-content: flex-end;
                align-items: center;
              "
            >
              <p style="width: 90px; text-align: center; font-weight: bold">
                问题类型：
              </p>
              <el-input
                size="small"
                style="width: 130px; margin-left: 16px"
                clearable
                v-model="qusetionInfo.problem"
                placeholder="请输入"
              >
              </el-input>
            </div>
          </el-form-item>
        </div>
        <el-form-item prop="remarks">
          <div style="display: flex">
            <p style="width: 64px; text-align: right; font-weight: bold">
              备注：
            </p>
            <el-input
              type="textarea"
              :autosize="{ minRows: 2, maxRows: 4 }"
              placeholder="请输入内容"
              v-model="qusetionInfo.problemRemarks"
            >
            </el-input>
          </div>
        </el-form-item>
        <el-form-item prop="">
          <div
            style="
              display: flex;
              align-items: center;
              justify-content: center;
              width: 100%;
              position: relative;
            "
          >
            <canvas
              v-if="xiaFaDialog"
              class="edit-canvas"
              ref="editCanvas"
            ></canvas>
          </div>
        </el-form-item>

        <div style="margin-top: 20px; text-align: center">
          <el-button
            @click="cloneTab"
            style="
              background-color: #f3f6fd;
              color: #303e9d;
              width: 100px;
              height: 40px;
              font-weight: bold;
              font-size: 14px;
            "
            size="small"
            >取 消
          </el-button>
          <el-button
            @click="_submit"
            style="
              background-color: #303e9d;
              color: #eeeeee;
              width: 100px;
              height: 40px;
              font-weight: bold;
              font-size: 14px;
            "
            size="small"
            >保 存
          </el-button>
        </div>
      </el-form>
    </el-dialog>
  </div>
</template>

<script>
import test from './test.vue'
import dayjs from 'dayjs'
import videojs from 'video.js'
import 'video.js/dist/video-js.css'
import flvjs from 'flv.js'
import { number } from 'echarts'

export default {
  name: 'openCctv',
  components: {
    test,
  },
  data() {
    return {
      startTimeObj: null, // 用于存储 dayjs 格式的开始时间
      orderInfo: {},
      value1: '',
      activeName: '监控',
      duration: 0,
      durationTotail: 0, // 历史视频总时长（秒）
      currentTime: 0, // 当前播放时间（秒）
      playbackSpeed: 0.5,
      startTime: '',
      stopTime: '',
      timeVal: [],
      optionsPlaybackSpeed: [
        {
          label: '0.5x',
          value: 0.5,
        },
        {
          label: '1x',
          value: 1,
        },
        {
          label: '2x',
          value: 2,
        },
      ],
      edieaCanvasWidth: 0,
      xiaFaDialog: false,
      openDialog: false,
      myPlayer: null,
      assignTaskId: '',
      serialNumber: '',
      dataURLImage: '',
      qusetionInfo: {
        problemRemarks: '',
        problem: '',
      },
      videoContainer: '',

      // 画笔状态
      isDrawing: false,
      lastX: 0,
      lastY: 0,
      // 画笔样式
      strokeColor: 'red',
      strokeWidth: 2,

      rules: {
        problem: [{ required: true, message: '请输入问题', trigger: 'blur' }],
        problemRemarks: [
          { required: true, message: '请输入备注', trigger: 'blur' },
        ],
      },
    }
  },
  methods: {
    // 计算回放 接口返回视频的总时长
    calculateTimeDiffFromFLVUrl(url) {
      // 1. 提取begin和end参数（正则匹配）
      const beginMatch = url.match(/begin=(\d{14})/)
      const endMatch = url.match(/end=(\d{14})/)
      if (!beginMatch || !endMatch) throw new Error('URL中未找到begin或end参数')

      const [, beginStr] = beginMatch
      const [, endStr] = endMatch

      // 2. 转换为Date对象
      const parseTime = (str) =>
        new Date(
          `${str.slice(0, 4)}-${str.slice(4, 6)}-${str.slice(6, 8)} ${str.slice(
            8,
            10
          )}:${str.slice(10, 12)}:${str.slice(12, 14)}`
        )
      const beginDate = parseTime(beginStr)
      const endDate = parseTime(endStr)

      // 3. 计算秒差
      return Math.floor((endDate - beginDate) / 1000) * 1000
    },
    selectChange(e) {
      console.log('下拉改变', e)
      this.playbackSpeed = Number(e)
      if (this.videoElement) {
        this.videoElement.playbackRate = e // 关键：同步倍速到视频
      }
      this.changeHistoryVideo()
    },
    handleClick(e) {
      console.log('activeName', this.activeName)
      if (this.activeName === '回放') {
        this.startTime = ''
        this.stopTime = ''
        this.timeVal = []
        this.playbackSpeed = 0.5
        this.flvPlayer.destroy()
        this.flvPlayer = null
        const videoContainer = this.$refs.videoContainer
        videoContainer.removeChild(this.videoElement)
        return
      } else {
        this.changeHistoryVideo()
      }
    },
    changeHistoryVideo() {
      // 回放模式：必须选择时间范围才请求
      if (this.activeName === '回放' && (!this.startTime || !this.stopTime)) {
        this.$message.warning('请先选择回放时间范围')
        return
      }
      this.$api
        .firmCameraGetLiveAddress(
          this.activeName === '回放'
            ? {
                serialNumber: this.serialNumber,
                type: 2,
                startTime: this.startTime,
                stopTime: this.stopTime,
                playbackSpeed: this.playbackSpeed,
              }
            : { serialNumber: this.serialNumber, type: 1 }
        )
        .then((res) => {
          console.log('点击历史', res)
          this.$nextTick(() => {
            // this.durationTotail = this.calculateTimeDiffFromFLVUrl(res)
            // console.log('视频总时长', this.durationTotail)

            this.createVideoElement(res)
          })
        })
    },
    chooseTime(e) {
      if (!e) return
      // console.log('完时间')
      // const now = dayjs()

      // this.startTime = dayjs(dayjs(e).add(1, 's')).format('YYYY-MM-DD HH:mm:ss')
      // this.stopTime = now.format('YYYY-MM-DD HH:mm:ss')

      this.startTime = dayjs(e[0]).format('YYYY-MM-DD HH:mm:ss')
      this.stopTime = dayjs(e[1]).format('YYYY-MM-DD HH:mm:ss')
      // 新增：同时创建一个 dayjs 对象
      this.startTimeObj = dayjs(e[0])
      this.changeHistoryVideo()
    },

    // 格式化时间（秒 → MM:SS 或 HH:MM:SS）
    formatTime(seconds) {
      if (!seconds || isNaN(seconds)) return '00:00'
      const h = Math.floor(seconds / 3600)
      const m = Math.floor((seconds % 3600) / 60)
      const s = Math.floor(seconds % 60)
      // 若有小时则显示 HH:MM:SS，否则显示 MM:SS
      return h > 0
        ? `${h.toString().padStart(2, '0')}:${m.toString().padStart(2, '0')}:${s
            .toString()
            .padStart(2, '0')}`
        : `00:${m.toString().padStart(2, '0')}:${s.toString().padStart(2, '0')}`
    },
    handleProgressDrag(e) {
      this.currentTime = parseFloat(e.target.value)
    },
    // 拖动进度条结束（跳转至指定时间）
    handleProgressChange(e) {
      const targetTime = parseFloat(e.target.value)
      // this.videoElement.currentTime = targetTime; // 视频跳转到指定时间
      this.currentTime = targetTime
    },
    // 2. 初始化编辑画布的鼠标事件
    initEditCanvasEvents() {
      const editCanvas = this.$refs.editCanvas
      if (!editCanvas) return

      // 使用箭头函数 (=>) 来确保方法内部的 this 指向 Vue 实例
      editCanvas.addEventListener('mousedown', this.startDrawing)
      editCanvas.addEventListener('mousemove', this.draw)
      editCanvas.addEventListener('mouseup', this.stopDrawing)
      editCanvas.addEventListener('mouseout', this.stopDrawing)
    },
    // 3. 截图功能
    handleCapture() {
      if (!this.videoElement || !this.videoElement.videoWidth) {
        this.$message.error('视频尚未准备好，请稍候再试！')
        return
      }

      this.captureScreenshot()
    },
    // 截图
    captureScreenshot() {
      const video = document.getElementById('videoPlayer')
      console.log('video', video)

      // 1. 获取视频文件的原始尺寸和视频元素的显示尺寸
      const videoRealWidth = video.videoWidth // 视频文件本身的宽度（如1280）
      const videoRealHeight = video.videoHeight // 视频文件本身的高度（如720）

      // 2 创建一个不可见的canvas元素
      const canvas = document.createElement('canvas')
      // 设置canvas的尺寸与视频一致
      canvas.width = videoRealWidth
      // this.edieaCanvasWidth = JSON.parse(videoRealWidth) + 20
      canvas.height = videoRealHeight
      const context = canvas.getContext('2d')

      // console.log(
      //   'videoNaturalWidth-videoNaturalHeight',
      //   videoNaturalWidth,
      //   videoNaturalHeight
      // )

      context.drawImage(video, 0, 0, canvas.width, canvas.height)
      const dataURL = canvas.toDataURL('image/png')
      this.dataURLImage = dataURL
      this.videoElement.pause()
      this.xiaFaDialog = true
      this.qusetionInfo = this.$options.data.call(this).qusetionInfo
      this.setBackgroundImage(canvas.toDataURL('image/png'))
    },

    // 4. 将截图设置为编辑画布的背景
    setBackgroundImage(dataURL) {
      this.$nextTick(() => {
        const editCanvas = this.$refs.editCanvas
        // const editCanvas = document.getElementById('editCanvas')
        console.log('setBackgroundImage', editCanvas)
        const ctx = editCanvas.getContext('2d')
        const img = new Image()
        img.src = dataURL
        // // 1. 确保画布的绘图尺寸正确
        // const canvasWidth = 800
        // const canvasHeight = 500
        // editCanvas.width = canvasWidth
        // editCanvas.height = canvasHeight

        img.onload = () => {
          console.log('背景图的大小', img.width, img.height)

          // 设置编辑画布的尺寸与视频显示尺寸一致
          editCanvas.width = 800
          editCanvas.height = 450
          // editCanvas.width = img.width
          // editCanvas.height = img.height
          // 绘制背景图
          ctx.clearRect(0, 0, editCanvas.width, editCanvas.height)
          ctx.drawImage(img, 0, 0, editCanvas.width, editCanvas.height)

          // // 2. 计算图片的原始宽高比
          // const imgAspectRatio = img.width / img.height
          // // 3. 计算画布的宽高比
          // const canvasAspectRatio = canvasWidth / canvasHeight
          // let drawWidth, drawHeight, offsetX, offsetY
          // // 4. 根据宽高比决定如何缩放和定位
          // if (imgAspectRatio > canvasAspectRatio) {
          //   // 图片更宽，以宽度为准进行缩放
          //   drawWidth = canvasWidth
          //   drawHeight = canvasWidth / imgAspectRatio
          //   offsetX = 0
          //   offsetY = (canvasHeight - drawHeight) / 2 // 垂直居中
          // } else {
          //   // 图片更高或等比，以高度为准进行缩放
          //   drawHeight = canvasHeight
          //   drawWidth = canvasHeight * imgAspectRatio
          //   offsetY = 0
          //   offsetX = (canvasWidth - drawWidth) / 2 // 水平居中
          // }
          // // 5. 清除画布
          // ctx.clearRect(0, 0, canvasWidth, canvasHeight)
          // // 6. 在计算好的位置绘制缩放后的图片
          // ctx.drawImage(img, offsetX, offsetY, drawWidth, drawHeight)
        }
        // 初始化编辑画布的事件监听
        this.initEditCanvasEvents()
      })
    },

    // 5. 画笔相关方法
    startDrawing(e) {
      e.preventDefault()
      this.isDrawing = true
      const rect = this.$refs.editCanvas.getBoundingClientRect()
      this.lastX = e.clientX - rect.left
      this.lastY = e.clientY - rect.top
    },

    draw(e) {
      if (!this.isDrawing) return

      const ctx = this.$refs.editCanvas.getContext('2d')
      const rect = this.$refs.editCanvas.getBoundingClientRect()
      const currentX = e.clientX - rect.left
      const currentY = e.clientY - rect.top

      ctx.beginPath()
      ctx.moveTo(this.lastX, this.lastY)
      ctx.lineTo(currentX, currentY)
      ctx.strokeStyle = this.strokeColor
      ctx.lineWidth = this.strokeWidth
      ctx.lineCap = 'round'
      ctx.stroke()

      this.lastX = currentX
      this.lastY = currentY
    },

    stopDrawing() {
      this.isDrawing = false
    },
    base64ToBlob(base64Data) {
      const arr = base64Data.split(',')
      const mime = arr[0].match(/:(.*?);/)[1]
      const bstr = atob(arr[1])
      let n = bstr.length
      const u8arr = new Uint8Array(n)
      while (n--) {
        u8arr[n] = bstr.charCodeAt(n)
      }
      return new Blob([u8arr], { type: mime })
    },
    // 6. 保存编辑后的图片
    async saveEditedImage() {
      const editCanvas = this.$refs.editCanvas
      // if (!editCanvas.getContext('2d').getImageData(0, 0, 1, 1).data[3]) {
      //   alert('请先截图再保存！');
      //   return;
      // }
      const dataURL = editCanvas.toDataURL('image/png')
      const blob = this.base64ToBlob(dataURL)
      const formData = new FormData()
      formData.append('file', blob, 'image.png')
      const resUrl = await this.$api.imgFileImgUrl(formData)
      const data = {
        ...this.qusetionInfo,
        problemImg: resUrl.toString(),
        assignTaskId: this.assignTaskId,
      }
      const resData = await this.$api.assignAddProblem(data)
      if (resData == 1) this.xiaFaDialog = false
      return this.$message.success('保存成功！')
      // const link = document.createElement('a')
      // link.href = dataURL
      // link.download = 'edited-screenshot.png'
      // document.body.appendChild(link)
      // link.click()
      // document.body.removeChild(link)
    },
    async _submit() {
      this.$refs.supplierForm.validate(async (valid) => {
        if (!valid) return false
        try {
          console.log('操作')
          this.saveEditedImage()
        } catch (err) {
          console.error('接口请求出错：', err)
          this.$message.error('操作失败，请稍后重试')
        }
      })
    },
    cloneTab() {
      console.log('取消')
      this.$nextTick(() => {
        const editCanvas = this.$refs.editCanvas
        if (editCanvas) {
          editCanvas.removeEventListener('mousedown', this.startDrawing)
          editCanvas.removeEventListener('mousemove', this.draw)
          editCanvas.removeEventListener('mouseup', this.stopDrawing)
          editCanvas.removeEventListener('mouseout', this.stopDrawing)
        }
        this.xiaFaDialog = false
      })
    },
    init(res, row, assignTaskId, orderInfo = {}) {
      this.activeName = '监控'
      this.startTime = ''
      this.stopTime = ''
      this.timeVal = []
      console.log(res, row)
      this.openDialog = true
      this.$nextTick(() => {
        this.createVideoElement(res)
        // this.setUrl(
        //   'https://dragon.online-convert.com/download-file/6d7cae97-500e-497b-9c7d-2b41db497920/c7afff05-4f36-480b-b7bb-9075619782ca'
        // )
      })
      this.serialNumber = row
      this.assignTaskId = assignTaskId
      this.orderInfo = orderInfo
    },
    // createVideoElement(el) {
    //   console.log(el)
    //   const videoContainer = this.$refs.videoContainer
    //   videoContainer.innerHTML = ''
    //   const videoElement = document.createElement('video')
    //   videoElement.id = 'videoPlayer'
    //   videoElement.className = 'video-js'
    //   videoElement.setAttribute('controls', true)
    //   videoElement.setAttribute('preload', 'auto')
    //   // videoElement.setAttribute('width', '800')
    //   // videoElement.setAttribute('height', '500')
    //   videoElement.style.width = '800px' // 注意要加 'px' 单位
    //   videoElement.style.height = '500px'
    //   videoElement.setAttribute('crossorigin', 'anonymous') //新加
    //   this.videoElement = videoElement
    //   videoElement.muted = true
    //   videoContainer.appendChild(videoElement)
    //   videoElement.src = el
    //   videoElement.load() // 加载新视频
    //   videoElement.play() // 自动播放（可选）
    // },
    //需要换成支持flv格式的
    createVideoElement(el) {
      console.log(el)
      const videoContainer = this.$refs.videoContainer
      videoContainer.innerHTML = ''
      const videoElement = document.createElement('video')
      videoElement.id = 'videoPlayer'
      videoElement.className = 'video-js'
      videoElement.setAttribute('controls', true)
      videoElement.setAttribute('preload', 'auto')
      videoElement.style.width = '800px'
      videoElement.style.height = '500px'
      videoElement.setAttribute('crossorigin', 'anonymous')
      videoElement.muted = true
      videoContainer.appendChild(videoElement)
      // 保存引用
      this.videoElement = videoElement
      // 判断是否是 flv 格式
      if (flvjs.isSupported() && el.includes('.flv')) {
        if (this.flvPlayer) {
          this.flvPlayer.destroy()
          this.flvPlayer = null
        }
        this.flvPlayer = null
        if (this.activeName === '回放') {
          console.log('回放')

          const flvPlayer = flvjs.createPlayer({
            type: 'flv',
            url: el,
            isLive: false, // 或 true，视情况而定
            hasAudio: false, // 👈 禁用音频轨道
            hasVideo: true,
            duration: this.durationTotail,
            // 1. 启用分离的线程来解析FLV，提高性能和稳定性
            enableWorker: true,
            // 2. 启用懒加载，这是实现 seek 的前提
            lazyLoad: true,
            // 3. 预加载足够的数据来解析元数据（特别是 duration）
            // 这个值可以根据你的视频平均时长调整，例如 10 * 60 = 600 秒
            lazyLoadMaxDuration: 120000,
            stashInitialSize: 128000, // 增加初始缓存
            // 4. 预加载足够的数据来建立关键帧索引
            // 这个值很重要，太小可能无法建立完整索引
            preloadTime: 10,
            // 5. 指定 seek 模式
            // 'range'：通过 HTTP Range 请求直接跳到文件指定位置，速度快，是最佳选择
            // 'keyframe'：在已加载的数据中寻找最近的关键帧，不支持跨未加载区域跳转
            seekType: 'range',

            // 6. 与 seekType: 'range' 配合使用，指定每次 Range 请求的大小
            seekPointDuration: 5,
          })
          this.flvPlayer = flvPlayer
          this.flvPlayer.on(flvjs.Events.METADATA_ARRIVED, (metadata) => {
            // metadata 中包含 duration（总时长），手动赋值给 videoElement
            if (metadata.duration) {
              this.duration = metadata.duration
              this.videoElement.duration = metadata.duration // 强制同步总时长
              console.log('FLV 元数据加载成功，总时长：', this.duration)
            }
          })
          // 监听元数据加载（获取总时长） // 监听 video 原生 loadedmetadata（双重保障）
          // 监听 metadata 加载完成（获取总时长，原生进度条依赖此值）
          // 监听 video 原生 loadedmetadata（双重保障）
          videoElement.addEventListener(
            'loadedmetadata',
            () => {
              if (videoElement.duration && !isNaN(videoElement.duration)) {
                console.log('videoElement', videoElement)

                this.duration = videoElement.duration
                console.log(
                  '原生 video 元数据加载成功，总时长：',
                  this.duration
                )
              } else {
                console.warn('原生 video 未获取到时长，尝试从 FLV 元数据补充')
              }
            },
            { once: true }
          )

          // 监听 seek 完成（确保拖动进度条后视频正常跳转）
          this.flvPlayer.on(flvjs.Events.SEEKED, () => {
            this.currentTime = videoElement.currentTime
            console.log('进度条跳转完成，当前时间1：', this.currentTime)
          })

          // 监听 seek 完成（确保拖动进度条后，视频正常跳转）
          this.videoElement.addEventListener('seeked', () => {
            console.log('进度条跳转完成，当前时间2：', videoElement.currentTime)
            this.currentTime = videoElement.currentTime
            if (this.flvPlayer) {
              this.flvPlayer.seek(this.currentTime)
            }
          })
          this.videoElement.addEventListener('timeupdate', () => {
            console.log('进度条跳转完成，当前时间3：', videoElement.currentTime)
          })

          this.videoElement.addEventListener('seeking', () => {
            console.log(
              '进度条拖动中，当前临时时间4：',
              this.formatTime(videoElement.currentTime)
            )
            // 可选：拖动中显示“加载中”状态
          })
        } else {
          console.log('直播')
          const flvPlayer = flvjs.createPlayer({
            type: 'flv',
            url: el,
            isLive: true, // 或 true，视情况而定
            hasAudio: false, //  禁用音频轨道
            hasVideo: true,
          })
          this.flvPlayer = flvPlayer
        }

        this.flvPlayer.attachMediaElement(videoElement)

        this.flvPlayer.load()
        this.flvPlayer.play()
      } else {
        // 兼容 mp4 等普通格式
        videoElement.src = el
        videoElement.load()
        videoElement.play()
      }
    },
    setUrl(nowPlayVideoUrl) {
      // 销毁旧播放器
      if (this.myPlayer) {
        if (typeof this.myPlayer.destroy === 'function') {
          this.myPlayer.destroy()
        } else if (typeof this.myPlayer.dispose === 'function') {
          this.myPlayer.dispose()
        }
        this.myPlayer = null
      }

      const isFlv = /\.flv(\?|$)/i.test(nowPlayVideoUrl)

      if (isFlv && flvjs.isSupported()) {
        const videoElement = document.getElementById('videoPlayer')
        const flvPlayer = flvjs.createPlayer({
          type: 'flv',
          url: nowPlayVideoUrl,
          isLive: true,
          hasAudio: false,
          hasVideo: true,
        })
        flvPlayer.attachMediaElement(videoElement)
        flvPlayer.load()
        flvPlayer.play()
        this.myPlayer = flvPlayer
      } else {
        const options = {
          autoplay: true,
          controls: true,
          width: 800,
          height: 500,
          notSupportedMessage: '网络不稳定，请稍后再试~',
          sources: [
            {
              src: nowPlayVideoUrl,
              type: 'application/x-mpegURL',
            },
          ],
        }
        this.myPlayer = videojs('videoPlayer', options)
      }
    },
    close() {
      this.openDialog = false
      if (this.flvPlayer) {
        this.flvPlayer.destroy()
        this.flvPlayer = null
      }
    },

    beforeDestroy() {
      if (this.myPlayer) {
        if (typeof this.myPlayer.destroy === 'function') {
          this.myPlayer.destroy()
        } else if (typeof this.myPlayer.dispose === 'function') {
          this.myPlayer.dispose()
        }
        this.myPlayer = null
      }
    },
    async switchCctv(val) {
      try {
        const token = await this.$api.firmCameraGetFirmCameraAccessToken()
        if (!token) throw new Error('获取 Token 失败')
        const res = await this.$api.firmCameraGetListAllCamera({
          serialNumber: this.serialNumber,
        })
        const channelId = JSON.parse(res)[0].channelId
        await this.$api.firmCameraYunVideoStart2({
          serialNumber: this.serialNumber,
        })
        // 云台控制逻辑可自行恢复
      } catch (error) {
        console.error('失败:', error.response?.data || error.message)
      }
    },
  },
}
</script>

<style scoped lang="less">
@import '../../../assets/css/public.css';

// @import '../../assets/css/public.css';
/* 控制栏样式 */
.control-bar {
  margin-top: 10px;
  padding: 10px;
  background: #f5f5f5;
  border-radius: 4px;
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 15px;
}
.row-tow {
  display: flex;
  flex-direction: row;
  justify-content: space-between;
  align-content: center;
}

.edit-canvas {
  border: 1px solid #ccc;
  cursor: crosshair;

  /* 
   * 核心解决方案：
   * 禁止用户选择画布上的内容，从而阻止拖动行为。
   * 我们为不同的浏览器添加了前缀以确保兼容性。
   */
  -webkit-user-select: none; /* Safari */
  -moz-user-select: none; /* Firefox */
  -ms-user-select: none; /* IE/Edge */
  user-select: none; /* 标准语法 */
}
</style>

<!--flv格式-->
<!--<template>-->
<!--  <div id="player">-->
<!--    <el-dialog :visible.sync="openDialog" @close="close" title="监控画面" width="40%">-->
<!--      <div style="width: 100%;height: 100%; display: flex; justify-content: center">-->
<!--        <div ref="videoContainer">-->
<!--          &lt;!&ndash; Video element will be injected here &ndash;&gt;-->
<!--        </div>-->
<!--      </div>-->
<!--    </el-dialog>-->
<!--  </div>-->
<!--</template>-->

<!--<script>-->
<!--import videojs from 'video.js'-->
<!--import 'video.js/dist/video-js.css'-->
<!--import flvjs from 'flv.js'-->

<!--export default {-->
<!--  name: "openCctv",-->
<!--  data() {-->
<!--    return {-->
<!--      openDialog: false,-->
<!--      myPlayer: null,-->
<!--      serialNumber: "",-->
<!--    }-->
<!--  },-->
<!--  methods: {-->
<!--    init(url, row) {-->
<!--      this.openDialog = true-->
<!--      this.$nextTick(() => {-->
<!--        this.createVideoElement()-->
<!--        this.setUrl(url)-->
<!--      })-->
<!--      this.serialNumber = row-->
<!--    },-->
<!--    createVideoElement() {-->
<!--      const videoContainer = this.$refs.videoContainer-->
<!--      videoContainer.innerHTML = ''-->
<!--      const videoElement = document.createElement('video')-->
<!--      videoElement.id = 'videoPlayer'-->
<!--      videoElement.className = 'video-js'-->
<!--      videoElement.setAttribute('controls', true)-->
<!--      videoElement.setAttribute('preload', 'auto')-->
<!--      videoElement.setAttribute('width', '800')-->
<!--      videoElement.setAttribute('height', '500')-->
<!--      videoElement.muted = true-->
<!--      videoContainer.appendChild(videoElement)-->
<!--    },-->
<!--    setUrl(nowPlayVideoUrl) {-->
<!--      // 销毁旧播放器-->
<!--      if (this.myPlayer) {-->
<!--        if (typeof this.myPlayer.destroy === 'function') {-->
<!--          this.myPlayer.destroy()-->
<!--        } else if (typeof this.myPlayer.dispose === 'function') {-->
<!--          this.myPlayer.dispose()-->
<!--        }-->
<!--        this.myPlayer = null-->
<!--      }-->

<!--      const isFlv = /\.flv(\?|$)/i.test(nowPlayVideoUrl)-->

<!--      if (isFlv && flvjs.isSupported()) {-->
<!--        const videoElement = document.getElementById('videoPlayer')-->
<!--        const flvPlayer = flvjs.createPlayer({-->
<!--          type: 'flv',-->
<!--          url: nowPlayVideoUrl,-->
<!--          isLive: true,-->
<!--          hasAudio: false,-->
<!--          hasVideo: true-->
<!--        })-->
<!--        flvPlayer.attachMediaElement(videoElement)-->
<!--        flvPlayer.load()-->
<!--        flvPlayer.play()-->
<!--        this.myPlayer = flvPlayer-->
<!--      } else {-->
<!--        const options = {-->
<!--          autoplay: true,-->
<!--          controls: true,-->
<!--          width: 800,-->
<!--          height: 500,-->
<!--          notSupportedMessage: "网络不稳定，请稍后再试~",-->
<!--          sources: [-->
<!--            {-->
<!--              src: nowPlayVideoUrl,-->
<!--              type: 'application/x-mpegURL',-->
<!--            },-->
<!--          ],-->
<!--        }-->
<!--        this.myPlayer = videojs('videoPlayer', options)-->
<!--      }-->
<!--    },-->
<!--    close() {-->
<!--      this.openDialog = false-->
<!--      if (this.myPlayer) {-->
<!--        if (typeof this.myPlayer.destroy === 'function') {-->
<!--          this.myPlayer.destroy()-->
<!--        } else if (typeof this.myPlayer.dispose === 'function') {-->
<!--          this.myPlayer.dispose()-->
<!--        }-->
<!--        this.myPlayer = null-->
<!--      }-->
<!--    },-->
<!--    beforeDestroy() {-->
<!--      if (this.myPlayer) {-->
<!--        if (typeof this.myPlayer.destroy === 'function') {-->
<!--          this.myPlayer.destroy()-->
<!--        } else if (typeof this.myPlayer.dispose === 'function') {-->
<!--          this.myPlayer.dispose()-->
<!--        }-->
<!--        this.myPlayer = null-->
<!--      }-->
<!--    },-->
<!--    async switchCctv(val) {-->
<!--      try {-->
<!--        const token = await this.$api.firmCameraGetFirmCameraAccessToken()-->
<!--        if (!token) throw new Error('获取 Token 失败')-->
<!--        const res = await this.$api.firmCameraGetListAllCamera({serialNumber: this.serialNumber})-->
<!--        const channelId = JSON.parse(res)[0].channelId-->
<!--        await this.$api.firmCameraYunVideoStart2({serialNumber: this.serialNumber})-->
<!--        // 云台控制逻辑可自行恢复-->
<!--      } catch (error) {-->
<!--        console.error('失败:', error.response?.data || error.message)-->
<!--      }-->
<!--    }-->
<!--  },-->
<!--}-->
<!--</script>-->

<!--<style scoped lang="less">-->

<!--/deep/.video-js{-->
<!--  width: 500px !important;-->
<!--  height: 300px !important;-->

<!--}-->
<!--</style>-->

<!--m3u8格式-->
<!--<template>-->
<!--  <div id="player">-->
<!--    <el-dialog :visible.sync="openDialog" @close="close" title="监控画面" center>-->
<!--      <div style="width: 100%;display: flex;justify-content: center">-->
<!--        <div ref="videoContainer">-->
<!--          &lt;!&ndash; Video element will be injected here &ndash;&gt;-->
<!--        </div>-->
<!--      </div>-->
<!--      &lt;!&ndash;      <div style="display: flex;margin-top: 20px;width: 200px;justify-content: space-evenly">&ndash;&gt;-->
<!--      &lt;!&ndash;        <el-link style="color: #66b1ff;text-decoration: underline" @click="switchCctv('0')">向上</el-link>&ndash;&gt;-->
<!--      &lt;!&ndash;        <el-link style="color: #66b1ff;text-decoration: underline" @click="switchCctv('1')">向下</el-link>&ndash;&gt;-->
<!--      &lt;!&ndash;        <el-link style="color: #66b1ff;text-decoration: underline" @click="switchCctv('2')">向左</el-link>&ndash;&gt;-->
<!--      &lt;!&ndash;        <el-link style="color: #66b1ff;text-decoration: underline" @click="switchCctv('3')">向右</el-link>&ndash;&gt;-->
<!--      &lt;!&ndash;      </div>&ndash;&gt;-->
<!--    </el-dialog>-->
<!--  </div>-->
<!--</template>-->

<!--<script>-->
<!--import Videojs from 'video.js'-->
<!--import 'video.js/dist/video-js.css'-->
<!--import axios from "axios";-->

<!--export default {-->
<!--  name: "openCctv",-->
<!--  data() {-->
<!--    return {-->
<!--      openDialog: false,-->
<!--      myPlayer: null,-->
<!--      serialNumber: "",-->
<!--    }-->
<!--  },-->
<!--  methods: {-->
<!--    init(url, row) {-->
<!--      this.openDialog = true-->
<!--      this.$nextTick(() => {-->
<!--        this.createVideoElement()-->
<!--        this.setUrl(url)-->
<!--      })-->
<!--      this.serialNumber = row-->
<!--    },-->
<!--    createVideoElement() {-->
<!--      const videoContainer = this.$refs.videoContainer-->
<!--      videoContainer.innerHTML = ''-->
<!--      const videoElement = document.createElement('video')-->
<!--      videoElement.id = 'videoPlayer'-->
<!--      videoElement.className = 'video-js'-->
<!--      videoElement.muted = true-->
<!--      videoContainer.appendChild(videoElement)-->
<!--    },-->
<!--    setUrl(nowPlayVideoUrl) {-->
<!--      const options = {-->
<!--        autoplay: true,-->
<!--        controls: true,-->
<!--        width: "800px",-->
<!--        height: "500px",-->
<!--        notSupportedMessage: "网络不稳定，请稍后再试~",-->
<!--        sources: [-->
<!--          {-->
<!--            src: nowPlayVideoUrl,-->
<!--            type: 'application/x-mpegURL',-->
<!--            cors: true,-->
<!--          },-->
<!--        ],-->
<!--      }-->

<!--      this.myPlayer = Videojs('videoPlayer', options)-->
<!--    },-->
<!--    close() {-->
<!--      this.openDialog = false-->
<!--      if (this.myPlayer) {-->
<!--        this.myPlayer.dispose()-->
<!--        this.myPlayer = null-->
<!--      }-->
<!--    },-->
<!--    beforeDestroy() {-->
<!--      if (this.myPlayer) {-->
<!--        this.myPlayer.dispose()-->
<!--        this.myPlayer = null-->
<!--      }-->
<!--    },-->
<!--    async switchCctv(val) {-->
<!--      try {-->
<!--        // 获取 token-->
<!--        const token = await this.$api.firmCameraGetFirmCameraAccessToken();-->
<!--        if (!token) throw new Error('获取 Token 失败');-->
<!--        // 获取channel列表-->
<!--        const res = await this.$api.firmCameraGetListAllCamera({serialNumber: this.serialNumber});-->
<!--        // if (!Array.isArray(res) || res.length === 0) throw new Error('未找到摄像头信息');-->
<!--        const channelId = JSON.parse(res)[0].channelId;-->

<!--        const res2 = await this.$api.firmCameraYunVideoStart2({serialNumber: this.serialNumber})-->
<!--        // console.log(res2)-->
<!--        // 开始云台控制 云眸外部接口-->
<!--        //   const url = `https://api2.hik-cloud.com/siot/video/api/channels/${channelId}/ptz/start`;-->
<!--        //   const postData = {-->
<!--        //     direction: val,-->
<!--        //     speed: 2,-->
<!--        //   };-->
<!--        //   const headers = {-->
<!--        //     'Content-Type': 'application/json',-->
<!--        //     'Authorization': `Bearer ${token}`-->
<!--        //   };-->
<!--        //   const response = await axios.post(url, postData, {headers});-->
<!--        //   console.log('成功:', response.data);-->
<!--      } catch (error) {-->
<!--        console.error('失败:', error.response?.data || error.message);-->
<!--      }-->
<!--    }-->
<!--  },-->
<!--}-->
<!--</script>-->

<!--<style scoped>-->
<!--/*.video-js {*/-->
<!--/*  width: 100% !important;*/-->
<!--/*}*/-->
<!--</style>-->
